/*
 * Scheduler.c
 *
 *  Created on: Mar 12, 2012
 *      Author: Tosshunter
 */
#include "Scheduler.h"
Queue priority_4 = createQueue(100);
Queue priority_3 = createQueue(100);
Queue priority_2 = createQueue(100);
Queue priority_1 = createQueue(100);

/*
 * Constructor for scheduler using a given type.
 */
Scheduler * createScheduler (SchedulerType type) {
	Scheduler * scheduler;
	Queue que1 = createQueue(100);
	Queue que2 = createQueue(100);
	scheduler = malloc(sizeof(Scheduler));
	switch (type) {
	case ROUND_ROBIN:
		scheduler -> ready = que1;
		scheduler -> blocked = que2;
		scheduler -> type = type;
		break;
	case PRIORITY:
		scheduler -> blocked = que2;
		scheduler->list = malloc(sizeof 4);
		scheduler->list[0] = priority_4;
		scheduler->list[1] = priority_3;
		scheduler->list[2] = priority_2;
		scheduler->list[3] = priority_1;
		scheduler -> type = type;
		break;
	case LOTTERY:
		array_list_init(scheduler->lotteryPot, 100);
		scheduler -> type = type;
		scheduler -> ready = que1;
		scheduler -> blocked = que2;
		break;
	}
	return scheduler;
}

/*
 * Switches the running processes depending on schedule's type.
 */
void schedule(Scheduler *sh) {
	switch(sh -> type) {
	case PRIORITY:
		if(!IsEmpty(sh->list[0])){
			sh->running = FrontAndDequeue(sh-> list[0]);
			sh->running->state = RUNNING;
		} else if (!IsEmpty(sh->list[1])) {
			sh->running = FrontAndDequeue(sh-> list[1]);
			sh->running->state = RUNNING;
		} else if (!IsEmpty(sh->list[2])) {
			sh->running = FrontAndDequeue(sh-> list[2]);
			sh->running->state = RUNNING;
		} else if (!IsEmpty(sh->list[3])){
			sh->running = FrontAndDequeue(sh-> list[3]);
			sh->running->state = RUNNING;
		} else {

		}
		break;
	case ROUND_ROBIN:
		sh->running = FrontAndDequeue(sh-> ready);
		sh->running->state = RUNNING;
		break;
	case LOTTERY:
		int winner = 0;
		int size = sh->ready.Size;
		int i;
		int j;
		while (winner == 0) {
			int chosenTicket = random()%100;
			for (i = 0; i < size; i++) {
				PCBStr* pcb = FrontAndDequeue(sh->ready);
				for (j = 0; j < pcb->process->tickets.size; j++){
					if (array_list_get(pcb->process->tickets, j) == chosenTicket) {
						winner = 1;
						array_list_remove(pcb->process->tickets, j);
						sh->running = pcb;
						sh->running->state = RUNNING;
						break;
					}
				}
				if (winner == 0) {
					Enqueue(pcb, sh->ready);
				}
			}
		}
		break;

	}
}

/*
 * Checks if the process is blocked.
 */
void checkBlocked(Scheduler *sh, int block) {
	int i;
	int size = sh->blocked.Size;
		for (i = 0; i < size; i++) {
			PCBStr* pcb = FrontAndDequeue(sh->blocked);
			switch (pcb->waiting_on) {
			case 1:
				if (block == 1) {
					pcb -> state = RUNNING;
					sh -> running = pcb;
				} else {
					Enqueue(pcb, sh->blocked);
				}
				break;
			case 2:
				if (block == 2) {
					pcb -> state = RUNNING;
					sh -> running = pcb;
				} else {
					Enqueue(pcb, sh->blocked);
				}
				break;

		}
		break;
	}
}
